/**
 * @file widget.cpp
 * @brief 计算器应用程序的主要实现文件
 * @details 实现了一个支持基本四则运算和小数运算的计算器
 *          使用栈结构实现中缀表达式求值算法
 * @author 计算器开发者
 * @date 2024
 */

#include "widget.h"
#include "ui_widget.h"

/**
 * @brief 构造函数，初始化计算器界面和样式
 * @param parent 父窗口指针
 * @details 设置窗口标题、图标、背景色和各种按钮样式
 */
Widget::Widget(QWidget *parent)
    : QWidget(parent), ui(new Ui::Widget)
{
    // 设置UI界面
    ui->setupUi(this);
    this->setWindowTitle("计算器");

    // 设置窗口图标
    this->setWindowIcon(QIcon(":/maliao"));

    // 创建调色板并设置主窗口背景颜色为浅绿色
    QPalette palette;
    palette.setColor(QPalette::Window, QColor(229, 249, 247));
    this->setPalette(palette);

    // 设置记录显示区域的样式（半透明黑色文字）
    ui->record->setStyleSheet("color: rgba(0, 0, 0, 0.5);");

    // 设置等号按钮为蓝色背景
    ui->equalBtn->setStyleSheet("background-color:rgba(23, 117, 197);");

    // 设置运算符按钮为浅绿色背景
    ui->addBtn->setStyleSheet("background-color:rgba(242, 252, 251);");
    ui->subBtn->setStyleSheet("background-color:rgba(242, 252, 251);");
    ui->mulBtn->setStyleSheet("background-color:rgba(242, 252, 251);");
    ui->deleteBtn->setStyleSheet("background-color:rgba(242, 252, 251);");
    ui->divBtn->setStyleSheet("background-color:rgba(242, 252, 251);");
    ui->floatBtn->setStyleSheet("background-color:rgba(242, 252, 251);");
    ui->clsBtn->setStyleSheet("background-color:rgba(242, 252, 251);");

    // 设置显示区域为透明背景，无边框，粗体字
    ui->show->setStyleSheet("background-color:transparent;border-width:0;border-style:outset;font-weight:bold");
    ui->record->setStyleSheet("background-color:transparent;border-width:0;border-style:outset");

    // 设置边框样式
    ui->boder->setStyleSheet("border-width:5;");

    // 初始化显示为0
    expression = "0";
    ui->show->setText(expression);
}

/**
 * @brief 析构函数，释放UI资源
 */
Widget::~Widget()
{
    delete ui;
}

// ==================== 数字按钮事件处理 ====================

/**
 * @brief 数字1按钮点击事件
 * @details 如果当前显示为0，则替换为1；否则在末尾添加1
 */
void Widget::on_oneBtn_clicked()
{
    if (!expression.isEmpty() && expression.back() == ')')
    {
        expression += "*";
    }
    if (expression == "0")
    {
        expression = "1";
    }
    else
    {
        expression += "1";
    }
    ui->show->setText(expression);
}

/**
 * @brief 数字2按钮点击事件
 */
void Widget::on_twoBtn_clicked()
{
    if (!expression.isEmpty() && expression.back() == ')')
    {
        expression += "*";
    }
    if (expression == "0")
    {
        expression = "2";
    }
    else
    {
        expression += "2";
    }
    ui->show->setText(expression);
}

/**
 * @brief 数字3按钮点击事件
 */
void Widget::on_threeBtn_clicked()
{
    if (!expression.isEmpty() && expression.back() == ')')
    {
        expression += "*";
    }
    if (expression == "0")
    {
        expression = "3";
    }
    else
    {
        expression += "3";
    }
    ui->show->setText(expression);
}

/**
 * @brief 数字4按钮点击事件
 */
void Widget::on_fourBtn_clicked()
{
    if (!expression.isEmpty() && expression.back() == ')')
    {
        expression += "*";
    }
    if (expression == "0")
    {
        expression = "4";
    }
    else
    {
        expression += "4";
    }
    ui->show->setText(expression);
}

/**
 * @brief 数字5按钮点击事件
 */
void Widget::on_fiveBtn_clicked()
{
    if (!expression.isEmpty() && expression.back() == ')')
    {
        expression += "*";
    }
    if (expression == "0")
    {
        expression = "5";
    }
    else
    {
        expression += "5";
    }
    ui->show->setText(expression);
}

/**
 * @brief 数字6按钮点击事件
 */
void Widget::on_sixBtn_clicked()
{
    if (!expression.isEmpty() && expression.back() == ')')
    {
        expression += "*";
    }
    if (expression == "0")
    {
        expression = "6";
    }
    else
    {
        expression += "6";
    }
    ui->show->setText(expression);
}

/**
 * @brief 数字7按钮点击事件
 */
void Widget::on_sevenBtn_clicked()
{
    if (!expression.isEmpty() && expression.back() == ')')
    {
        expression += "*";
    }
    if (expression == "0")
    {
        expression = "7";
    }
    else
    {
        expression += "7";
    }
    ui->show->setText(expression);
}

/**
 * @brief 数字8按钮点击事件
 */
void Widget::on_eightBtn_clicked()
{
    if (!expression.isEmpty() && expression.back() == ')')
    {
        expression += "*";
    }
    if (expression == "0")
    {
        expression = "8";
    }
    else
    {
        expression += "8";
    }
    ui->show->setText(expression);
}

/**
 * @brief 数字9按钮点击事件
 */
void Widget::on_nineBtn_clicked()
{
    if (!expression.isEmpty() && expression.back() == ')')
    {
        expression += "*";
    }
    if (expression == "0")
    {
        expression = "9";
    }
    else
    {
        expression += "9";
    }
    ui->show->setText(expression);
}

/**
 * @brief 数字0按钮点击事件
 * @details 如果当前不是0，则在末尾添加0；否则保持0不变
 */
void Widget::on_zeroBtn_clicked()
{
    if (!expression.isEmpty() && expression.back() == ')')
    {
        expression += "*";
    }
    if (expression != "0")
    {
        expression += "0";
    }
    ui->show->setText(expression);
}

// ==================== 运算符和括号按钮事件处理 ====================

/**
 * @brief 左括号按钮点击事件
 * @details 先处理连续操作符，然后添加左括号
 */
void Widget::on_leftBtn_clicked()
{
    inputContinuousOpt();
    if (expression == "0")
    {
        expression = "(";
    }
    else
    {
        // 检查前一个字符，如果前一个字符是数字，则添加乘号
        if (!expression.isEmpty() && (expression.back().isDigit()|| expression.back()==')'))
        {
            expression += "*(";
        }
        else
        {
            expression += "(";
        }
    }
    ui->show->setText(expression);
}

/**
 * @brief 右括号按钮点击事件
 * @details 先处理连续操作符，然后添加右括号
 */
void Widget::on_rightBtn_clicked()
{
    inputContinuousOpt();
    if (expression == "0")
    {
        // 如果表达式为空或只有0，不允许直接输入右括号
        return;
    }
    else
    {
        // 检查是否已经有左括号，且前一个字符不是操作符
        int leftCount = 0, rightCount = 0;
        for (int i = 0; i < expression.length(); i++)
        {
            if (expression[i] == '(')
                leftCount++;
            else if (expression[i] == ')')
                rightCount++;
        }

        // 只有当左括号数量大于右括号数量时才允许输入右括号
        if (leftCount > rightCount)
        {
            // 检查前一个字符，如果前一个字符是操作符，则不允许输入右括号
            if (!expression.isEmpty() && (expression.back() == '+' || expression.back() == '-' ||
                                          expression.back() == '*' || expression.back() == '/' ||
                                          expression.back() == '('))
            {
                return;
            }
            expression += ")";
        }
    }
    ui->show->setText(expression);
}

/**
 * @brief 加法按钮点击事件
 * @details 先处理连续操作符，然后添加加号
 */
void Widget::on_addBtn_clicked()
{
    inputContinuousOpt();
    expression += "+";
    ui->show->setText(expression);
}

/**
 * @brief 减法按钮点击事件
 * @details 先处理连续操作符，然后添加减号
 */
void Widget::on_subBtn_clicked()
{
    inputContinuousOpt();
    expression += "-";
    ui->show->setText(expression);
}

/**
 * @brief 乘法按钮点击事件
 * @details 先处理连续操作符，然后添加乘号
 */
void Widget::on_mulBtn_clicked()
{
    inputContinuousOpt();
    expression += "*";
    ui->show->setText(expression);
}

/**
 * @brief 除法按钮点击事件
 * @details 先处理连续操作符，然后添加除号
 */
void Widget::on_divBtn_clicked()
{
    inputContinuousOpt();
    expression += "/";
    ui->show->setText(expression);
}

// ==================== 功能按钮事件处理 ====================

/**
 * @brief 清除按钮点击事件
 * @details 清空表达式，重置显示为0，清空历史记录
 */
void Widget::on_clsBtn_clicked()
{
    expression = "0";
    ui->show->setText(expression);
    ui->record->clear();
}

/**
 * @brief 删除按钮点击事件
 * @details 删除最后一个字符，如果只剩一个字符则重置为0
 */
void Widget::on_deleteBtn_clicked()
{
    if (expression.size() > 1)
    {
        expression.chop(1);
    }
    else
    {
        expression = "0";
    }
    ui->show->setText(expression);
}

/**
 * @brief 小数点按钮点击事件
 * @details 先处理连续操作符，然后添加小数点
 */
void Widget::on_floatBtn_clicked()
{
    inputContinuousOpt();
    expression += ".";
    ui->show->setText(expression);
}

// ==================== 核心计算功能 ====================

/**
 * @brief 获取操作符的优先级
 * @param a 操作符字符
 * @return 优先级数值（数值越大优先级越高）
 * @details 优先级规则：
 *          - 加减法：优先级1
 *          - 乘除法：优先级2
 *          - 幂运算：优先级3
 *          - 左括号：优先级4（最高，用于括号内运算）
 */
int Widget::Priority(char a)
{
    int value = 0;

    switch (a)
    {
    case '+':
    case '-':
        value = 1; // 加减法优先级最低
        break;
    case '*':
    case '/':
        value = 2; // 乘除法优先级中等
        break;
    case '^':
        value = 3; // 幂运算优先级较高
        break;
    case '(':
        value = 4; // 左括号优先级最高
        break;
    default:
        value = 0; // 其他字符优先级为0
    }

    return value;
}

/**
 * @brief 等号按钮点击事件 - 执行表达式计算
 * @details 使用栈结构实现中缀表达式求值算法
 *          算法步骤：
 *          1. 遍历表达式中的每个字符
 *          2. 遇到数字：解析完整数字并压入数字栈
 *          3. 遇到左括号：压入操作符栈
 *          4. 遇到右括号：弹出操作符并计算，直到遇到左括号
 *          5. 遇到操作符：比较优先级，弹出高优先级操作符并计算
 *          6. 最后处理剩余操作符
 */
void Widget::on_equalBtn_clicked()
{
    // 如果表达式为空，显示0
    if (expression.isEmpty())
    {
        ui->show->setText("0");
        return;
    }

    // 检查括号匹配
    int leftBrackets = 0, rightBrackets = 0;
    for (int i = 0; i < expression.length(); i++)
    {
        if (expression[i] == '(')
            leftBrackets++;
        else if (expression[i] == ')')
            rightBrackets++;
    }

    if (leftBrackets != rightBrackets)
    {
        ui->show->setText("Error: 括号不匹配");
        return;
    }

    // 新增括号合法性检查
    QString errMsg;
    if (!checkBracketOperatorValid(expression, errMsg))
    {
        ui->show->setText(errMsg);
        return;
    }

    // 检查括号内容是否合法（不能只有操作符）
    for (int i = 0; i < expression.length(); ++i)
    {
        if (expression[i] == '(')
        {
            int j = i + 1;
            // 找到下一个右括号
            while (j < expression.length() && expression[j] != ')')
                ++j;
            if (j < expression.length())
            {
                QString inside = expression.mid(i + 1, j - i - 1);
                QString trimmed = inside.trimmed();
                // 如果括号内为空或全是操作符
                if (trimmed.isEmpty() || trimmed.contains(QRegExp("^[+\-*/.]+$")))
                {
                    ui->show->setText("Error: 括号内容非法");
                    return;
                }
            }
        }
    }

    // 创建数字栈和操作符栈
    QStack<double> s_num; // 存储数字
    QStack<char> s_opt;   // 存储操作符

    char opt[128] = {0}; // 字符数组存储表达式
    int i = 0;           // 遍历索引

    // 将QString转换为char数组
    QByteArray ba = expression.toLatin1();
    strcpy(opt, ba.data());

    // 遍历表达式中的每个字符
    while (opt[i] != '\0')
    {
        // 处理数字和小数点（包括负数）
        if ((opt[i] >= '0' && opt[i] <= '9') || opt[i] == '.' ||
            (opt[i] == '-' && (i == 0 || opt[i - 1] == '(' ||
                               (opt[i - 1] == '+' || opt[i - 1] == '-' || opt[i - 1] == '*' || opt[i - 1] == '/'))))
        {
            QString numStr; // 临时存储数字字符串

            // 如果是负号，先添加负号
            if (opt[i] == '-')
            {
                numStr += opt[i];
                i++;
            }

            // 连续读取数字和小数点，组成完整数字
            while ((opt[i] >= '0' && opt[i] <= '9') || opt[i] == '.')
            {
                numStr += opt[i];
                i++;
            }

            // 转换为double类型并验证格式
            bool ok;
            double num = numStr.toDouble(&ok);
            if (!ok)
            {
                ui->show->setText("Error: 数字格式错误");
                return;
            }
            s_num.push(num); // 压入数字栈
        }
        // 处理左括号
        else if (opt[i] == '(')
        {
            s_opt.push(opt[i]); // 直接压入操作符栈
            i++;
        }
        // 处理右括号
        else if (opt[i] == ')')
        {
            // 弹出操作符并计算，直到遇到左括号
            while (!s_opt.empty() && s_opt.top() != '(')
            {
                calcOnce(s_num, s_opt);
            }
            // 检查是否找到了对应的左括号
            if (!s_opt.empty() && s_opt.top() == '(')
            {
                s_opt.pop(); // 弹出左括号
            }
            else
            {
                ui->show->setText("Error: 括号不匹配");
                return;
            }
            i++;
        }
        // 处理四则运算符
        else if (opt[i] == '+' || opt[i] == '-' || opt[i] == '*' || opt[i] == '/')
        {
            // 比较优先级，弹出高优先级操作符并计算
            while (!s_opt.empty() && s_opt.top() != '(' && Priority(opt[i]) <= Priority(s_opt.top()))
            {
                calcOnce(s_num, s_opt);
            }
            s_opt.push(opt[i]); // 压入当前操作符
            i++;
        }
        // 跳过其他字符（如空格等）
        else
        {
            i++;
        }
    }

    // 处理剩余的操作符
    while (!s_opt.empty())
    {
        // 检查是否还有未匹配的左括号
        if (s_opt.top() == '(')
        {
            ui->show->setText("Error: 括号不匹配");
            return;
        }
        calcOnce(s_num, s_opt);
    }

    // 显示计算结果
    if (!s_num.empty())
    {
        // 使用'g'格式自动去除多余的小数零
        ui->show->setText(QString::number(s_num.top(), 'g', 10));
    }
    else
    {
        ui->show->setText("Error: 计算失败");
    }

    // 在历史记录中显示表达式
    ui->record->setText(expression + "=");
    expression.clear(); // 清空表达式，准备下一次计算
    expression += '0';
}

/**
 * @brief 执行一次运算操作
 * @param s_num 数字栈的引用
 * @param s_opt 操作符栈的引用
 * @details 从栈中弹出两个数字和一个操作符，执行运算后将结果压回数字栈
 *          支持加法、减法、乘法、除法四种运算
 *          包含除零检查和错误处理
 */
void Widget::calcOnce(QStack<double> &s_num, QStack<char> &s_opt)
{
    // 检查栈中是否有足够的数字和操作符
    if (s_opt.empty())
    {

        return; // 如果操作符栈为空，直接返回
    }

    // 检查数字栈中是否有足够的数字
    if (s_num.size() < 2)
    {
        // 只有在操作符栈不为空时才检查操作符类型
        if (!s_opt.empty() && (s_opt.top() == '+' || s_opt.top() == '-' || s_opt.top() == '*' || s_opt.top() == '/'))
        {
            s_num.push(0);
            if(expression.isEmpty()==false &&(expression.back()<'0'||expression.back()>'9'))
            {
                expression+='0';
            }

        }
        else
        {
            return;
        }
    }

    // 弹出两个操作数（注意顺序：b是第二个操作数，a是第一个操作数）
    double b = s_num.top();
    s_num.pop(); // 第二个操作数
    double a = s_num.top();
    s_num.pop(); // 第一个操作数

    // 弹出操作符
    char op = s_opt.top();
    s_opt.pop();

    double res = 0; // 存储计算结果

    // 根据操作符执行相应的运算
    switch (op)
    {
    case '+':
        res = a + b;
        break;
    case '-':
        res = a - b;
        break;
    case '*':
        res = a * b;
        break;
    case '/':
        // 检查除零错误
        if (b == 0)
        {
            ui->show->setText("Error: 除零错误");
            return;
        }
        else
        {
            res = a / b;
        }
        break;
    default:
        ui->show->setText("Error: 未知操作符");
        return;
    }

    // 将计算结果压回数字栈
    s_num.push(res);
}

// ==================== 辅助功能函数 ====================

/**
 * @brief 处理连续操作符输入
 * @details 当用户连续输入操作符时，自动删除前一个操作符
 *          避免表达式出现连续操作符的情况
 *          例如：1++2 会被处理成 1+2
 */
void Widget::inputContinuousOpt()
{
    // 如果表达式为空，直接返回
    if (expression.isEmpty())
    {
        return;
    }

    bool is_pop = false;         // 标记是否需要删除最后一个字符
    QChar c = expression.back(); // 获取最后一个字符
    char ch = c.toLatin1();      // 转换为char类型

    // 检查最后一个字符是否为操作符或括号
    switch (ch)
    {
    case '+':
        is_pop = true;
        break;
    case '-':
        is_pop = true;
        break;
    case '*':
        is_pop = true;
        break;
    case '/':
        is_pop = true;
        break;
    case '.':
        is_pop = true;
        break; // 小数点也作为操作符处理
    }

    // 如果需要删除，则删除最后一个字符
    if (is_pop)
    {
        expression.chop(1);
    }
}

/**
 * @brief 显示文本变化事件处理
 * @param arg1 变化后的文本内容
 * @details 当显示文本发生变化时，确保表达式不为空
 *          如果表达式为空，则设置为"0"
 */
void Widget::on_show_textChanged(const QString &arg1)
{
    // 如果表达式为空，设置为0
    if (expression.isEmpty())
    {
        expression = "0";
        ui->show->setText(expression);
    }
}

// 注释掉的数字验证函数（已不再使用）
// bool Widget::isDigital(QString str)
//{
//    if (str.isEmpty())
//        return false;
//
//    for (int i = 0; i < str.size(); i++)
//    {
//        QChar ch = str.at(i);
//        if (ch == '-' && i == 0 && str.size() > 1)
//        { // 允许负数开头
//            continue;
//        }
//        if (ch == '.' && str.count('.') == 1)
//        { // 允许一个小数点
//            continue;
//        }
//        if (ch < '0' || ch > '9')
//        {
//            return false;
//        }
//    }
//    return true;
//}

// ==================== 表达式合法性检查 ====================
/**
 * @brief 检查表达式中括号后的运算符是否合法
 * @param expr 待检查的表达式
 * @return 合法返回true，否则返回false
 */
bool Widget::checkBracketOperatorValid(const QString &expr, QString &errMsg)
{
    for (int i = 0; i < expr.length(); ++i)
    {
        // 左括号后不能直接接*或/
        if (expr[i] == '(' && i + 1 < expr.length())
        {
            if (expr[i + 1] == '*' || expr[i + 1] == '/')
            {
                errMsg = "Error: 左括号后不能直接接*或/";
                return false;
            }
        }
        // 右括号前不能直接接+ - * /
        if (expr[i] == ')' && i - 1 >= 0)
        {
            if (expr[i - 1] == '+' || expr[i - 1] == '-' || expr[i - 1] == '*' || expr[i - 1] == '/')
            {
                errMsg = "Error: 右括号前不能直接接+、-、*、/";
                return false;
            }
        }
    }
    return true;
}
